package com.tyj.movie.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.tyj.movie.config.interceptor.LoginInterceptor;
import com.tyj.movie.constant.OrderStatusEnum;
import com.tyj.movie.constant.RedisConstant;
import com.tyj.movie.entity.MovieTheatreOrder;
import com.tyj.movie.entity.MovieTheatreShow;
import com.tyj.movie.entity.Users;
import com.tyj.movie.mapper.MovieTheatreOrderMapper;
import com.tyj.movie.mapper.MovieTheatreShowMapper;
import com.tyj.movie.service.MovieTheatreOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tyj.movie.to.MovieTheatreOrderTo;
import com.tyj.movie.util.AlipayTemplate;
import com.tyj.movie.util.DateUtil;
import com.tyj.movie.util.SecurityUtil;
import com.tyj.movie.vo.OrderPayVo;
import com.tyj.movie.vo.OrderVo;
import com.tyj.movie.vo.PayVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author tyj
 * @since 2021-06-28
 */
@Service
public class MovieTheatreOrderServiceImpl extends ServiceImpl<MovieTheatreOrderMapper, MovieTheatreOrder> implements MovieTheatreOrderService {

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    MovieTheatreShowMapper movieTheatreShowMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    AlipayTemplate alipayTemplate;

    @Autowired
    MovieTheatreOrderMapper movieTheatreOrderMapper;

    @Override
    public Integer submitOrder(MovieTheatreOrderTo movieTheatreOrderTo) {
        //得到当前用户
        Users user = SecurityUtil.getSessionUser();

        //防重验证
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long execute = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(RedisConstant.USER_ORDER_TOKEN_PREFIX + user.getId()), movieTheatreOrderTo.getToken());
        if (execute == 0) {
            //防重验证失败返回1
            return 1;
        }

        //恶意下单验证
        BoundHashOperations<String, Object, Object> boundHashOperations = redisTemplate.boundHashOps(RedisConstant.USER_ORDER_SPITE_TOKEN);
        Object o = boundHashOperations.get(movieTheatreOrderTo.getMovieTheatreShowId() + "-" + user.getId());

        if (o != null && Integer.valueOf(o.toString()) >= 3) {
            return 2;
        }

        //座位验证
        //获得所有座位 采用分布式锁
        RLock lock = redissonClient.getLock(RedisConstant.LOCK_SEAT + user.getId());
        boolean seatState = true; //座位是否也被购买标记;
        String[] seats = movieTheatreOrderTo.getSeat().split(",");
        try {
            lock.lock(200, TimeUnit.MILLISECONDS);
            for (String seat : seats) {
                if (redisTemplate.opsForSet().isMember(RedisConstant.MOVIE_THEATRE_SEAT + movieTheatreOrderTo.getMovieTheatreShowId(), seat)) {
                    //已被购买标记为false
                    seatState = false;
                    break;
                }
            }
            if (!seatState) {
                //有被购买 返回状态2
                return 3;
            } else {
                String redisKey = RedisConstant.MOVIE_THEATRE_SEAT + movieTheatreOrderTo.getMovieTheatreShowId();
                //锁定座位
                redisTemplate.opsForSet().add(redisKey, seats);
                //计算过期时间
                Long expire = redisTemplate.getExpire(redisKey);
                if (expire == -1) {
                    //计算时间差 加上半天时间
                    Long second = DateUtil.getSecond(movieTheatreOrderTo.getEndDate(), new Date()) + 43200;
                    redisTemplate.expire(redisKey, second, TimeUnit.SECONDS);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        //金额验证
        //总价
        BigDecimal price = movieTheatreOrderTo.getPrice();
        //购买数量
        int buyNum = seats.length;
        //获得当前商品的单价价格
        String s = redisTemplate.opsForValue().get(RedisConstant.MOVIE_THEATRE_SHOW_PRICE + movieTheatreOrderTo.getMovieTheatreShowId());
        BigDecimal unitPrice = new BigDecimal(s);
        BigDecimal multiply = unitPrice.multiply(new BigDecimal(buyNum));
        if (multiply.compareTo(price) != 0) {
            return 4;
        }

        //恶意下单数据更新
        //判断是否存在
        if (boundHashOperations.hasKey(movieTheatreOrderTo.getMovieTheatreShowId() + "-" + user.getId())) {
            //存在赋值为自增
            boundHashOperations.put(movieTheatreOrderTo.getMovieTheatreShowId() + "-" + user.getId(), Integer.valueOf(o.toString()) + 1 + "");
        } else {
            //不存在 赋值为1
            boundHashOperations.put(movieTheatreOrderTo.getMovieTheatreShowId() + "-" + user.getId(), 1 + "");
        }


        //发送消息
        MovieTheatreOrder movieTheatreOrder = new MovieTheatreOrder();
        movieTheatreOrderTo.setUserId(user.getId());
        movieTheatreOrderTo.setCreateDate(new Date());
        movieTheatreOrderTo.setOrderSn(IdWorker.getTimeId());
        movieTheatreOrderTo.setState(OrderStatusEnum.CREATE_NEW.getCode());
        BeanUtils.copyProperties(movieTheatreOrderTo, movieTheatreOrder);
        rabbitTemplate.convertAndSend("order-event-exchange", "send-order", movieTheatreOrder);
        return 0;
    }

    @Override
    public OrderPayVo queryOrderPayVo(String orderSn) {
        OrderPayVo orderPayVo = this.baseMapper.queryOrderPayVo(orderSn);
        return orderPayVo;
    }

    @Override
    public PayVo queryPayVoByOrderSn(String orderSn) {
        PayVo payVo = new PayVo();
        MovieTheatreOrder movieTheatreOrder = this.baseMapper.selectOne(new QueryWrapper<MovieTheatreOrder>().eq("order_sn", orderSn));
        payVo.setBody("结算");
        payVo.setOut_trade_no(movieTheatreOrder.getOrderSn());
        payVo.setSubject("猫眼电影结算");
        payVo.setTotal_amount(movieTheatreOrder.getPrice().toString());
        return payVo;
    }

    @Override
    public List<OrderVo> queryUserOrder() throws ParseException {
        Users user = SecurityUtil.getSessionUser();
        List<OrderVo> orderVoList = this.baseMapper.queryUserOrderByUserId(user.getId());
        for (OrderVo orderVo : orderVoList) {
            String dateFormat = DateUtil.getDateFormat(orderVo.getStartDate());
            orderVo.setStartDateStr(dateFormat);
        }
        return orderVoList;
    }

    @Override
    public Integer refund(String orderSn) throws AlipayApiException {
        //得到当前订单
        MovieTheatreOrder movieTheatreOrder = this.baseMapper.selectOne(new QueryWrapper<MovieTheatreOrder>().eq("order_sn", orderSn));
        //得到放映时间
        MovieTheatreShow movieTheatreShow = movieTheatreShowMapper.selectById(movieTheatreOrder.getMovieTheatreShowId());
        //判断订单是否在退单日期范围
        long time = movieTheatreShow.getStartDate().getTime(); //电影开始时间
        long time1 = new Date().getTime() + (1000 * 60 * 30); //现在时间
        //判断是否付款
        if (movieTheatreOrder.getState() != OrderStatusEnum.PAYED.getCode()) {
            return 0;
        }

        if (time1 - time >= 0) {
            //时间超过
            return 2;
        } else {
            //时间未超过 可以退款
            rabbitTemplate.convertAndSend("order-event-exchange", "refund-order", movieTheatreOrder);
            return 1;
        }
    }

}
